﻿using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime;
using System.Diagnostics;
using Nemerle.Assertions;

namespace Nemerle.Collections
{
  /// <summary>
  /// Description of ReadOnlyArray.
  /// </summary>
  [System.Serializable]
  [DebuggerNonUserCode]
  [System.Runtime.InteropServices.ComVisible(false)]
  [DebuggerDisplay("Length = {Length}: {ToString()}")]
  public class ReadOnlyArray[T] : IEnumerable[T]
  {
    public this(seq : IEnumerable[T])
      requires seq != null
    {
      _array = seq.ToArray();
    }

    public this(@array : array[T])
      requires @array != null
    {
      _array = @array;
    }
    
    private this(len : int)
      requires len >= 0
    {
      _array = array(len);
    } 
    
    _array : array[T];

    public Item[index : int] : T
    {
  		[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
      get { _array[index] }
    }
    
		public Count : int
		{
			[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
			get { _array.Length; }
		}

		public Length : int
		{
			[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
			get { _array.Length; }
		}

		public GetEnumerator() : IEnumerator[T]
		{
		  //_array :> IEnumerator[T]
		  def loop(ary : array[T], i : int) : void
		  {
		    when (i < ary.Length)
		    {
		      yield ary[i];
		      loop(ary, i + 1)
		    }
		  }
		  
		  loop(_array, 0)
		}
		
		public Map[To](convert : T -> To) : ReadOnlyArray[To]
		{
      ReadOnlyArray(MapToArray(convert))
		}
		
		public MapToArray[To](convert : T -> To) : array[To]
		{
		  def resultArray = array(_array.Length);
		  
		  foreach (elem in _array with i)
		    resultArray[i] = convert(elem);
		    
		  resultArray
		}
	}
}
